<template>
  <div class="html_details">
    <div class="left">
      <!-- <iframe ref="iframe" style="border: none" :src="fileUrls.html"></iframe> -->
      <iframe ref="iframe" style="border: none" :srcdoc="code"></iframe>
    </div>
    <div class="rigth">
      <Suspense>
        <template #default>
          <div class="editor">
            <div class="menu">
              <el-select-v2 v-model="activeFile" :options="files" placeholder="请选择文件" style="width: 240px"
                :props="{ value: 'path', label: 'fileNameEntirely' }" />
              <el-button type="primary" round @click="run">运行</el-button>
            </div>
            <monacoEditor :key="activeFile" v-model="fileCodes[(activeFile as string)]" :language="language">
            </monacoEditor>
          </div>
        </template>

        <template #fallback>
          <Loader2 />
        </template>
      </Suspense>
    </div>
  </div>
</template>

<script setup lang="ts">
// import monacoEditor from "@/components/monacoEditor/index.vue";
import { computed, ref, watch,defineAsyncComponent } from "vue";
import { useRoute } from "vue-router";
import { useAllFiles } from "@/store/allFiles";
import { allFilesNameAndPathItemType } from "@/store/allFiles.type";
import Loader2 from "@/components/loader/Loader2.vue";
  // 懒加载
  const monacoEditor = defineAsyncComponent(() => import('@/components/monacoEditor/index.vue'));
const store = useAllFiles();
const route = useRoute(); // 获取当前路由对象
let fileCodes = ref<{ [key: string]: string }>({}); // 所有文件代码
let fileUrls = ref<{ [key: string]: string }>({}); // 所有文件代码生成的blob url
let code = ref<string>(""); // 预览代码
const base = computed(() => route.query.base); // 根路径
let files = store.searchFilesBybase(base.value as string); // 文件信息
let rootFile = files.find((item) => item.isRoot) as allFilesNameAndPathItemType;
files = files.filter((item) => !item.isRoot);
files.push(rootFile);
let activeFile = ref(files.find((item) => item.isRoot)?.path); // 当前选中的文件

watch(
  () => base.value,
  (newValue) => {
    files = store.searchFilesBybase(newValue as string); // 文件信息
    rootFile = files.find((item) => item.isRoot) as allFilesNameAndPathItemType;
    files = files.filter((item) => !item.isRoot);
    files.push(rootFile);
    activeFile = ref(files.find((item) => item.isRoot)?.path); // 当前选中的文件
    getAllFilesInfo();
  }
);

// 声明 ref
const iframe = ref<HTMLIFrameElement | null>(null);
const language = computed(() => files.find((item) => item.path == activeFile.value)?.entirely);
// 获取文件信息
const getFileInfo = async (info: allFilesNameAndPathItemType) => {
  let isToString = ["html", "js", "css", "json", "jsx", "md"];
  let file = null;
  if (isToString.includes(info.entirely)) {
    file = await info?.moduleToString();
  } else {
    let module = await info?.module();
    file = module?.default;
  }
  fileCodes.value[info.path] = file;
};

// 创建 blob url
let createBlobUrlFromCode = function (code: string, type: string = "js") {
  // 文件扩展名到 MIME 类型的映射表
  const mimeTypes: { [key: string]: string } = {
    // 文本和代码文件
    js: "application/javascript",
    css: "text/css",
    html: "text/html",
    json: "application/json",
    xml: "application/xml",
    txt: "text/plain",

    // 图像文件
    png: "image/png",
    jpg: "image/jpeg",
    jpeg: "image/jpeg",
    gif: "image/gif",
    svg: "image/svg+xml",
    webp: "image/webp",
    bmp: "image/bmp",
    ico: "image/x-icon",

    // 视频文件
    mp4: "video/mp4",
    webm: "video/webm",
    ogg: "video/ogg",
    avi: "video/x-msvideo",
    mov: "video/quicktime",
    mpeg: "video/mpeg",

    // 音频文件
    mp3: "audio/mpeg",
    wav: "audio/wav",
    // ogg: "audio/ogg",
    flac: "audio/flac",
    aac: "audio/aac",

    // 字体文件
    ttf: "font/ttf",
    woff: "font/woff",
    woff2: "font/woff2",
    eot: "application/vnd.ms-fontobject",
    otf: "font/otf",

    // PDF 文件
    pdf: "application/pdf",

    // Office 文档
    doc: "application/msword",
    docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    xls: "application/vnd.ms-excel",
    xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    ppt: "application/vnd.ms-powerpoint",
    pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",

    // 压缩文件
    zip: "application/zip",
    rar: "application/x-rar-compressed",
    tar: "application/x-tar",
    gz: "application/gzip",

    // 其他文件类型
    csv: "text/csv",
    md: "text/markdown",
    yaml: "application/x-yaml",
    yml: "application/x-yaml",
    sh: "application/x-sh",
    bat: "application/x-bat",
    exe: "application/x-msdownload",
    ps1: "application/vnd.ms-powershell",

    // 默认类型
    "*": "application/octet-stream",
  };
  const blob = new Blob([code], { type: mimeTypes[type] });
  return URL.createObjectURL(blob);
};

// 获取所有文件信息
const getAllFilesInfo = async () => {
  await Promise.all(
    files.map(async (item) => {
      await getFileInfo(item);
    })
  );
  let rootFilePath = files.find((item) => item.isRoot)?.path as string;
  let baseUrl = getProtocolDomainAndPort() + base.value;
  fileCodes.value[rootFilePath] = fileCodes.value[rootFilePath]
    .replace(
      "</head>",
      `
          <style>
            html{
              width: 100%;
              height: 100%;
              padding: 0;
              margin: 0;
              box-sizing: border-box;
              overflow: auto;
            }
          </style>
          </head>`
    )
    .replace(
      "<head>",
      `<head>
  <base href="${baseUrl}">`
    );
  files.forEach((item) => {
    let url = createBlobUrlFromCode(fileCodes.value[item.path], item.entirely);
    code.value = fileCodes.value[rootFilePath].replace(`./${item.fileNameEntirely}`, url);
    fileUrls.value[item.entirely] = url;
  });
};
getAllFilesInfo();

const run = () => {
  let rootFilePath = files.find((item) => item.isRoot)?.path as string;
  code.value = fileCodes.value[rootFilePath];
  files.forEach((item) => {
    let url = createBlobUrlFromCode(fileCodes.value[item.path], item.entirely);
    code.value = code.value.replace(`./${item.fileNameEntirely}`, url);
    fileUrls.value[item.entirely] = url;
  });
};

const getProtocolDomainAndPort = function () {
  // 获取当前页面的协议
  var protocol = location.protocol;

  // 获取当前页面的主机名（域名）
  var hostname = location.hostname;

  // 获取当前页面的端口号，并处理默认端口情况
  var port = location.port || (protocol === "https:" ? 443 : 80);

  // 如果是默认端口，则不添加到结果字符串中
  if ((protocol === "https:" && port === 443) || (protocol === "http:" && port === 80)) {
    return `${protocol}//${hostname}`;
  } else {
    return `${protocol}//${hostname}:${port}`;
  }
};
</script>

<style lang="scss" scoped>
  .html_details {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    padding: 20px;
    box-sizing: border-box;

    .left,
    .rigth {
      width: 50%;
      height: 100%;
      padding: 20px;
      box-sizing: border-box;
    }

    .left iframe {
      width: 100%;
      height: 100%;
      border-radius: 10px;
      box-shadow: 20px 20px 26px #cacaca, -20px -20px 26px #f6f6f6;
      overflow: auto;
    }

    .rigth {
      position: relative;

      .editor {
        width: 100%;
        height: 100%;
      }
      .menu {
        display: flex;
        align-items: center;
        gap: 10px;
        position: absolute;
        right: 20px;
        top: 20px;
        transform: translateY(-100%);
        z-index: 2;
      }
    }
  }
</style>
